﻿using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ExpressionMapper.Tests
{
    [TestClass]
    public class CollectionMappingTests
    {
        [TestMethod]
        public void ArrayToAarrayTest()
        {
            var m = Mapper.Create<int?[], int[]>();
            var arr1 = new int?[] { 1, 2, 4 };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Length, arr2.Length);
            for (int i = 0; i < arr1.Length; i++)
            {
                Assert.AreEqual(arr1[i].Value, arr2[i]);
            }
        }

        [TestMethod]
        public void ListToListTest()
        {
            var m = Mapper.Create<List<int?>, List<int>>();
            var arr1 = new List<int?> { 1, 2, 4 };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i].Value, arr2[i]);
            }
        }

        #region Dictionary

        [TestMethod]
        public void DictionaryToDictionaryTest()
        {
            var m = Mapper.Create<Dictionary<int, Action>, Dictionary<int, Delegate>>();
            Action action = () => Console.Out.WriteLine("action!");

            Dictionary<int, Action> arr1 = new Dictionary<int, Action> { { 0, action }, { 1, null }, { 2, null }, { 3, null }, { 4, action } };
            Dictionary<int, Delegate> arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i], arr2[i]);
            }
        }

        [TestMethod]
        public void FromNameValueCollectionTest()
        {
            var m = Mapper.Create<NameValueCollection, Dictionary<int, double?>>();

            NameValueCollection arr1 = new NameValueCollection { { "0", null }, { "1", "1" }, { "2", "2" }, { "3", "-3" }, { "4", "0.4" } };
            Dictionary<int, double?> arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                if (string.IsNullOrEmpty(arr1[i]))
                    Assert.AreEqual(null, arr2[i]);
                else
                    Assert.AreEqual(arr1[i], arr2[i].ToString());
            }
        }

        [TestMethod]
        public void ToNameValueCollectionTest()
        {
            var m = Mapper.Create<Dictionary<int, Action>, Dictionary<int, Delegate>>();
            Action action = () => Console.Out.WriteLine("action!");

            Dictionary<int, Action> arr1 = new Dictionary<int, Action> { { 0, action }, { 1, null }, { 2, null }, { 3, null }, { 4, action } };
            Dictionary<int, Delegate> arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i], arr2[i]);
            }
        }

        [TestMethod]
        public void FromConcurrentDictionaryTest()
        {
            var m = Mapper.Create<ConcurrentDictionary<int, Action>, Dictionary<int, Delegate>>();
            Action action = () => Console.Out.WriteLine("action!");

            ConcurrentDictionary<int, Action> arr1 = new ConcurrentDictionary<int, Action>(new Dictionary<int, Action> { { 0, action }, { 1, null }, { 2, null }, { 3, null }, { 4, action } });
            Dictionary<int, Delegate> arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i], arr2[i]);
            }
        }

        [TestMethod]
        public void ToConcurrentDictionaryTest()
        {
            var m = Mapper.Create<IDictionary<int, Action>, ConcurrentDictionary<int, Delegate>>();
            Action action = () => Console.Out.WriteLine("action!");

            IDictionary<int, Action> arr1 = new Dictionary<int, Action> { { 0, action }, { 1, null }, { 2, null }, { 3, null }, { 4, action } };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i], arr2[i]);
            }
        }

        [TestMethod]
        public void FromStringDictionaryTest()
        {
            var m = Mapper.Create<StringDictionary, NameValueCollection>();

            StringDictionary arr1 = new StringDictionary { { "0", "x" }, { "1", "a" }, { "2", "b" }, { "3", "c" } };
            NameValueCollection arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i.ToString()], arr2[i]);
            }
        }

        [TestMethod]
        public void ToStringDictionaryTest()
        {
            var m = Mapper.Create<IDictionary<int, Type>, StringDictionary>();

            IDictionary<int, Type> arr1 = new Dictionary<int, Type> { { 0, typeof(object) }, { 1, typeof(int) }, { 2, typeof(string) }, { 3, typeof(DateTime) }, { 4, typeof(Action) } };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i].ToString(), arr2[i.ToString()]);
            }
        }

        [TestMethod]
        public void FromOrderedDictionaryTest()
        {
            var m = Mapper.Create<OrderedDictionary, NameValueCollection>();

            OrderedDictionary arr1 = new OrderedDictionary { { 0, 'x' }, { 1, 'a' }, { 2, 'b' }, { 3, 'c' } };
            NameValueCollection arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i].ToString(), arr2[i]);
            }
        }

        [TestMethod]
        public void ToOrderedDictionaryTest()
        {
            var m = Mapper.Create<IDictionary<int, string>, OrderedDictionary>();

            IDictionary<int, string> arr1 = new Dictionary<int, string> { { 0, typeof(object).Name }, { 1, typeof(int).Name },
            { 2, typeof(string).Name }, { 3, typeof(DateTime).Name }, { 4, typeof(Action).FullName } };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i], arr2[i]);
            }
        }

        [TestMethod]
        public void FromListDictionaryTest()
        {
            var m = Mapper.Create<ListDictionary, OrderedDictionary>();

            ListDictionary arr1 = new ListDictionary { { 0, 'x' }, { 1, 'a' }, { 2, 'b' }, { 3, 'c' } };
            OrderedDictionary arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i].ToString(), arr2[i].ToString());
            }
        }

        [TestMethod]
        public void ToListDictionaryTest()
        {
            var m = Mapper.Create<OrderedDictionary, ListDictionary>();

            OrderedDictionary arr1 = new OrderedDictionary { { 0, typeof(object).Name }, { 1, typeof(int).Name },
            { 2, typeof(string).Name }, { 3, typeof(DateTime).Name }, { 4, typeof(Action).FullName } };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1[i], arr2[i]);
            }
        }

        [TestMethod]
        public void FromHybridDictionaryTest()
        {
            var m = Mapper.Create<HybridDictionary, StringDictionary>();

            HybridDictionary arr1 = new HybridDictionary { { 0, "x" }, { "1", 'a' }, { 0.4f, 55 }, { -3, typeof(int) } };
            StringDictionary arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            foreach (var key in arr1.Keys)
            {
                Assert.AreEqual(arr1[key].ToString(), arr2[key.ToString()]);
            }
        }

        [TestMethod]
        public void ToHybridDictionaryTest()
        {
            var m = Mapper.Create<IDictionary<Delegate, int>, HybridDictionary>();

            IDictionary<Delegate, int> arr1 = new Dictionary<Delegate, int>
                                                 {
                                                     {(Func<int>)(() => 1), 1}
                                                     ,{(Func<int>)(() => 2), 2}
                                                     ,{(Func<int>)(() => 3), 3}
                                                     ,{(Func<int>)(() => 4), 4}
                                                     ,{(Func<int>)(() => 5), 5}

                                                 };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            foreach (var dlg in arr1.Keys)
            {
                Assert.AreEqual(arr1[dlg], arr2[dlg]);
            }
        }

        [TestMethod]
        public void FromHashtableTest()
        {
            var m = Mapper.Create<HybridDictionary, Hashtable>();

            HybridDictionary arr1 = new HybridDictionary { { 0, "x" }, { "1", 'a' }, { 0.4f, 55 }, { -3, typeof(int) } };
            Hashtable arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            foreach (var key in arr1.Keys)
            {
                Assert.AreEqual(arr1[key], arr2[key]);
            }
        }

        [TestMethod]
        public void ToHashtableTest()
        {
            var m = Mapper.Create<IDictionary<Delegate, int>, Hashtable>();

            IDictionary<Delegate, int> arr1 = new Dictionary<Delegate, int>
                                                 {
                                                     {(Func<int>)(() => 1), 1}
                                                     ,{(Func<int>)(() => 2), 2}
                                                     ,{(Func<int>)(() => 3), 3}
                                                     ,{(Func<int>)(() => 4), 4}
                                                     ,{(Func<int>)(() => 5), 5}

                                                 };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            foreach (var dlg in arr1.Keys)
            {
                Assert.AreEqual(arr1[dlg], arr2[dlg]);
            }
        }

        #endregion Dictionary

        #region ConcurrentCollections

        [TestMethod]
        public void ObjectDictionaryToDictionaryTest()
        {
            var m = Mapper.Create<IDictionary, Dictionary<int, int?>>();
            //Action action = () => Console.Out.WriteLine("action!");

            IDictionary arr1 = new Dictionary<int, int?> { { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 5 } };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Console.Out.WriteLine("Arr1: {0}\tArr2: {1}", arr1[i], arr2[i]);
                //Assert.AreEqual(arr1[i], arr2[i]);
            }
        }

        [TestMethod]
        public void FromBlockingCollectionTest()
        {
            var m = Mapper.Create<BlockingCollection<int>, List<int?>>();
            BlockingCollection<int> arr1 = new BlockingCollection<int> { 0, 1, 2, 3, 4 };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1.ElementAt(i), arr2[i]);
            }
        }

        [TestMethod]
        public void ToBlockingCollectionTest()
        {
            var m = Mapper.Create<List<int?>, BlockingCollection<int>>();
            List<int?> arr1 = new List<int?> { 0, 1, 2, null, 4 };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                var source = arr1.ElementAt(i);
                var target = arr2.ElementAt(i);
                if (source != null)
                    Assert.AreEqual(source, target);
                else
                {
                    Assert.AreEqual(0, target);
                }
            }
        }

        [TestMethod]
        public void FromConcurrentQueueTest()
        {
            var m = Mapper.Create<ConcurrentQueue<int>, List<int?>>();
            ConcurrentQueue<int> arr1 = new ConcurrentQueue<int>(new List<int> { 0, 1, 2, 3, 4 });

            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1.ElementAt(i), arr2[i]);
            }
        }

        [TestMethod]
        public void ToConcurrentQueueTest()
        {
            var m = Mapper.Create<IEnumerable<int?>, ConcurrentQueue<decimal>>();
            IEnumerable<int?> arr1 = new List<int?> { 0, 1, 2, null, 4 };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count(), arr2.Count);
            for (int i = 0; i < arr1.Count(); i++)
            {
                var source = arr1.ElementAt(i);
                var target = arr2.ElementAt(i);
                if (source != null)
                    Assert.AreEqual(source, (int)target);
                else
                {
                    Assert.AreEqual(0, target);
                }
            }
        }


        [TestMethod]
        public void FromObservableCollectionTest()
        {
            var m = Mapper.Create<ObservableCollection<int>, List<double>>();
            ObservableCollection<int> arr1 = new ObservableCollection<int>(new List<int> { 0, 1, 2, 3, 4 });

            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1.ElementAt(i), arr2[i]);
            }
        }

        [TestMethod]
        public void ToObservableCollectionTest()
        {
            var m = Mapper.Create<IList<float?>, ObservableCollection<ushort>>();
            IList<float?> arr1 = new List<float?> { 0, 1, 2, null, 4 };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                var source = arr1.ElementAt(i);
                var target = arr2.ElementAt(i);
                if (source != null)
                    Assert.AreEqual(source, target);
                else
                {
                    Assert.AreEqual(0, target);
                }
            }
        }

        [TestMethod]
        public void FromReadOnlyObservableCollectionTest()
        {
            var m = Mapper.Create<ReadOnlyObservableCollection<int>, BlockingCollection<uint>>();
            ReadOnlyObservableCollection<int> arr1 = new ReadOnlyObservableCollection<int>(new ObservableCollection<int> { 0, 1, 2, 3, 4 });

            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1.ElementAt(i), (int)arr2.ElementAt(i));
            }
        }

        [TestMethod]
        public void ToReadOnlyObservableCollectionTest()
        {
            var m = Mapper.Create<ConcurrentStack<float?>, ReadOnlyObservableCollection<ushort>>();
            ConcurrentStack<float?> arr1 = new ConcurrentStack<float?>(new List<float?> { 0, 1, 2, null, 4 });
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                var source = arr1.ElementAt(i);
                var target = arr2.ElementAt(i);
                if (source != null)
                    Assert.AreEqual(source, target);
                else
                {
                    Assert.AreEqual(0, target);
                }
            }
        }

        [TestMethod]
        public void FromReadOnlyCollectionTest()
        {
            var m = Mapper.Create<ReadOnlyCollection<double>, List<ulong>>();
            ReadOnlyCollection<double> arr1 = new ReadOnlyCollection<double>(new List<double> { 0, 1, 2, 3, 4 });

            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1.ElementAt(i), arr2[i]);
            }
        }

        [TestMethod]
        public void ToReadOnlyCollectionTest()
        {
            var m = Mapper.Create<ConcurrentQueue<string>, ReadOnlyCollection<DateTime>>();
            ConcurrentQueue<string> arr1 = new ConcurrentQueue<string>(new List<string> { "04.04.2004", "05.05.2005 13:14:15", "07.07.2007 13:12:11", "09.09.2012" });
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                var source = arr1.ElementAt(i);
                var target = arr2.ElementAt(i);
                if (source != null)
                {
                    if (target.Minute == 0)
                        Assert.AreEqual(source, target.ToString("MM.dd.yyyy"));
                    else
                        Assert.AreEqual(source, target.ToString("MM.dd.yyyy HH:mm:ss"));
                }
                else
                    Assert.Fail();
            }
        }

        #endregion ConcurrentCollections

        #region Stack

        [TestMethod]
        public void FromStackTest()
        {
            var m = Mapper.Create<List<int>, Stack<double>>();
            List<int> arr1 = new List<int>(new List<int> { 0, 1, 2, 3, 4 });

            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1.ElementAt(i), arr2.ElementAt(i));
            }
        }

        [TestMethod]
        public void ToStackTest()
        {
            var m = Mapper.Create<Stack<float?>, ObservableCollection<ushort>>();
            Stack<float?> arr1 = new Stack<float?>();
            arr1.Push(0);
            arr1.Push(1);
            arr1.Push(2); arr1.Push(null);
            arr1.Push(3);
            arr1.Push(4);
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                var source = arr1.ElementAt(i);
                var target = arr2.ElementAt(i);
                if (source != null)
                    Assert.AreEqual(source, target);
                else
                {
                    Assert.AreEqual(0, target);
                }
            }
        }

        [TestMethod]
        public void FromConcurrentStackTest()
        {
            var m = Mapper.Create<ConcurrentStack<int>, List<double>>();
            ConcurrentStack<int> arr1 = new ConcurrentStack<int>(new List<int> { 0, 1, 2, 3, 4 });

            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                Assert.AreEqual(arr1.ElementAt(i), arr2[i]);
            }
        }

        [TestMethod]
        public void ToConcurrentStackTest()
        {
            var m = Mapper.Create<ICollection<short?>, ConcurrentStack<float>>();
            ICollection<short?> arr1 = new List<short?> { 0, 1, 2, null, 4 };
            var arr2 = m(arr1);

            Assert.AreEqual(arr1.Count, arr2.Count);
            for (int i = 0; i < arr1.Count; i++)
            {
                var source = arr1.ElementAt(i);
                var target = arr2.ElementAt(i);
                if (source != null)
                    Assert.AreEqual(source, (short)target);
                else
                {
                    Assert.AreEqual(0, target);
                }
            }
        }

        #endregion Stack
    }
}
